package hku.cs.lunuo.launch;

import hku.cs.lunuo.util.LunuoLibHelper;
import hku.cs.lunuo.views.Ltest;
import hku.cs.lunuo.views.LtestCase;
import hku.cs.lunuo.views.LtestMethod;
import hku.cs.lunuo.views.LtestSuite;
import hku.cs.lunuo.views.RankView;
import hku.cs.lunuo.views.TestContentProvider;
import hku.cs.profile.Check;
import hku.cs.tools.DirTools;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.security.InvalidParameterException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.junit.JUnitCore;
import org.eclipse.jdt.junit.TestRunListener;
import org.eclipse.jdt.junit.model.ITestCaseElement;
import org.eclipse.jdt.junit.model.ITestElement;
import org.eclipse.jdt.junit.model.ITestRunSession;
import org.eclipse.jdt.junit.model.ITestSuiteElement;
import org.eclipse.jdt.junit.model.ITestElement.Result;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.PartInitException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

import soot.Scene;

public class LunuoAfterLaunchDelegate extends TestRunListener {
	private RankView viewer;
	private CheckboxTreeViewer treeViewer;
	private TableViewer tableViewer;
	private Ltest testConstruct;
	private String resultDirPath;
	private URL[] sootclassPath;
	private IJavaProject javaProject;

	private File conPath = null;

	private HashMap<String, HashMap<String, Boolean>> result = new HashMap<String, HashMap<String, Boolean>>();

	public LunuoAfterLaunchDelegate(String resultDirPath, IJavaProject javaProject,
			URL[] sootclassPath, IViewPart viewer, String rankAlgName) {
		this.resultDirPath = resultDirPath;
		this.sootclassPath = sootclassPath;
		this.javaProject = javaProject;
		this.viewer = (RankView) viewer;
		if (this.viewer == null)
			throw new InvalidParameterException();

		treeViewer = this.viewer.getTreeViewer();
		tableViewer = this.viewer.getTableViewer();
		this.viewer.setJavaProject(javaProject);
		this.viewer.setRankAlgName(rankAlgName);

		JUnitCore.addTestRunListener(this);
	}

	@Override
	public void sessionFinished(ITestRunSession session) {
		for (String rkey : result.keySet()) {
			HashMap<String, Boolean> inResult = result.get(rkey);

			Element xmlRoot = new Element("testcase");
			xmlRoot.setAttribute("name", rkey);
			xmlRoot.setAttribute("number", Integer.toString(inResult.size()));
			Document xmlDoc = new Document(xmlRoot);

			for (String key : inResult.keySet()) {
				Element xmlTestMethod = new Element("testmethod");
				xmlTestMethod.setAttribute("name", key);
				xmlTestMethod.setAttribute("status", ((Boolean) inResult
						.get(key)).toString());
				xmlRoot.addContent(xmlTestMethod);
			}

			try {
				File f = DirTools.prepare(resultDirPath + rkey);
				File fz = new File(f, "result.xml");
				new XMLOutputter().output(xmlDoc, new FileOutputStream(fz));
				System.out.println("write result file to " + fz.toString());
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//
		// Display.getDefault().asyncExec(new Runnable() {
		// public void run() {
		try {		
			Scene.v().setSootClassPath(LunuoLibHelper
					.urlsToString(sootclassPath));
			for (String rkey : result.keySet()) {
				HashMap<String, Boolean> inResult = result.get(rkey);
				String tmp = resultDirPath + rkey + File.separator;
				for (String key : inResult.keySet()) {
					String[] args = new String[] { tmp + key + File.separator };
					Check.main(args);
				}
				
//				new ComputeRank().doDir(new File(tmp), null);
//				new SuspMarker(javaProject.getElementName()).addMarkers(tmp);

			}
			Control ctrl = treeViewer.getControl();
			if (ctrl == null || ctrl.isDisposed())
				return;
			ctrl.getDisplay().syncExec(new Runnable() {
				public void run() {
					if (!treeViewer.getControl().isDisposed()) {
//						((List) treeViewer.getInput()).clear();
//						treeViewer.setInput(new Object());
//						treeViewer.refresh();
						((List) tableViewer.getInput()).clear();
						tableViewer.refresh();
						readTeststructure(conPath);
						treeViewer.setInput(new Ltest[]{testConstruct});
						((TestContentProvider)treeViewer.getContentProvider()).updateTreeCheck(testConstruct);
						
						LtestCase tst = findFirstTestCaseFromSuite(testConstruct);
						List<Ltest> lTstC = tst.getChildren();
						treeViewer.setChecked(tst, true);
						for(Ltest t : lTstC)
							treeViewer.setChecked(t, true);						
						try {
							viewer.fillTableViewer(tst);
							viewer.getAlgViewer().setSelection(new StructuredSelection(viewer.getRankAlgName()));
							viewer.getViewSite().getPage().showView(
									RankView.VIEW_ID);
						} catch (PartInitException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}

				
			});

		} catch (Exception ex) {
			ex.printStackTrace();
		}
		// }
		// });

		JUnitCore.removeTestRunListener(this);
		super.sessionFinished(session);
	}
	
	
	private LtestCase findFirstTestCaseFromSuite(Ltest test) {
		if( test instanceof LtestSuite){
			List<Ltest> lChildren = test.getChildren();
			for(Ltest t : lChildren){
				if (t instanceof LtestCase){
					return (LtestCase)t;
				}else if (t instanceof LtestSuite){
					return findFirstTestCaseFromSuite(t);
				}
			}
			
		}return null;
			
	}

	public boolean constructCate(ITestElement test, Element xmlE) {
		if (test instanceof ITestCaseElement) {
			Element e = new Element("testmethod");
			e.setAttribute("name", ((ITestCaseElement) test)
					.getTestMethodName());
			xmlE.addContent(e);
			return false;
		} else if (test instanceof ITestSuiteElement) {
			Element e = new Element("testsuite");
			e.setAttribute("name", ((ITestSuiteElement) test)
					.getSuiteTypeName());
			xmlE.addContent(e);
			boolean isTestCase = true;
			ITestElement[] ites = ((ITestSuiteElement) test).getChildren();
			for (ITestElement ite : ites) {
				if (constructCate(ite, e)) {
					isTestCase = false;
				}
			}
			if (isTestCase) {
				e.setName("testcase");
			}
			return true;
		}
		return true;
	}

	@Override
	public void sessionStarted(ITestRunSession session) {
		int a = resultDirPath.lastIndexOf('/');
		int b = resultDirPath.lastIndexOf('/', resultDirPath.length()-2);
		String c = resultDirPath.substring(b+1, a);
	
		
		Element xmlRoot = new Element("Test_Session");
		xmlRoot.setAttribute("name", c);
		Document xmlDoc = new Document(xmlRoot);
		ITestElement[] ites = session.getChildren();
		for (ITestElement ite : ites)
			constructCate(ite, xmlRoot);

		try {
			conPath = new File(DirTools.newTest(resultDirPath), "construct.xml");
			new XMLOutputter().output(xmlDoc, new FileOutputStream(conPath));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
//		Control ctrl = treeViewer.getControl();
//		if (ctrl == null || ctrl.isDisposed())
//			return;
//		ctrl.getDisplay().syncExec(new Runnable() {
//			public void run() {
//				if (!treeViewer.getControl().isDisposed()) {
//					
//				}
//			}
//		});
		super.sessionStarted(session);
	}

	@Override
	public void testCaseFinished(ITestCaseElement testCaseElement) {
		HashMap<String, Boolean> inMap = result.get(testCaseElement
				.getTestClassName());
		if (inMap == null)
			inMap = new HashMap<String, Boolean>();
		System.out.println(testCaseElement.getTestResult(true).toString());
		if (testCaseElement.getTestResult(true).equals(Result.OK)) {
			inMap.put(testCaseElement.getTestMethodName(), true);
		} else {
			inMap.put(testCaseElement.getTestMethodName(), false);
		}
		result.put(testCaseElement.getTestClassName(), inMap);
		super.testCaseFinished(testCaseElement);
	}

	@Override
	public void testCaseStarted(ITestCaseElement testCaseElement) {
		// TODO Auto-generated method stub
		super.testCaseStarted(testCaseElement);
	}

	private void readTestcase(Element e, Ltest t) {
		Iterator it = e.getChildren("testcase").iterator();
		while (it.hasNext()) {
			Element se = (Element) it.next();
			String name = se.getAttributeValue("name");
			// Test test = new Test(name, false, t, Test.TESTCASE);
			LtestCase test = new LtestCase(name, t);

			t.getChildren().add(test);

			Iterator i = se.getChildren("testmethod").iterator();
			while (i.hasNext()) {
				Element ese = (Element) i.next();
				String ename = ese.getAttributeValue("name");
				// Test etest = new Test(ename, false, test, Test.TESTMETHOD);
				LtestMethod etest = new LtestMethod(ename, test);
				test.getChildren().add(etest);
			}
		}
	}

	private void readTestsuite(Element e, Ltest t) {
		Iterator it = e.getChildren("testsuite").iterator();
		while (it.hasNext()) {
			Element se = (Element) it.next();
			String name = se.getAttributeValue("name");
			// Test test = new Test(name, false, t, Test.TESESUITE);
			LtestSuite test = new LtestSuite(name, t);
			t.getChildren().add(test);
			readTestsuite(se, test);
		}

		readTestcase(e, t);

	}

	private void readTeststructure(File f) {
		SAXBuilder sb = new SAXBuilder();
		try {
			Document xmlDoc = sb.build(f);
			Element xmlRoot = xmlDoc.getRootElement();
			
			testConstruct = new LtestSuite(xmlRoot.getAttributeValue("name"), null);
			readTestsuite(xmlRoot, testConstruct);
			

		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}
